﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using Noris.Tools.TraceVisualiser.Support;
using System.Drawing;
using Noris.Tools.TraceVisualiser.Components;

namespace Noris.Tools.TraceDownloader.Downloader
{
    internal class Config
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        public Config()
        {
            this.ConfigPrepare();
        }
        /// <summary>
        /// Konstruktor
        /// </summary>
        public Config(bool addDefault)
        {
            this.ConfigPrepare();
            if (this._PresetList.Count == 0 && addDefault)
                this.AddPreset(Preset.CreateDefault(true));
        }
        private void ConfigPrepare()
        {
            this.ConfigFile = System.IO.Path.Combine(Steward.MainExePath, ConfigName);
            this._PresetList = new List<Preset>();
            this.ConfigLoad();
        }
        internal static string ConfigName { get { return "TraceDownloader.config.xml"; } }
        /// <summary>
        /// Plný název XML souboru, kde je konfigurace ukládána
        /// </summary>
        internal string ConfigFile { get; private set; }
        /// <summary>
        /// Soupis všech presetů, které dosud nebyly vymazány
        /// </summary>
        internal IEnumerable<Preset> Presets { get { return this._PresetList.Where(p => !p.Deleted); } }
        /// <summary>
        /// Aktuálně vybraný Preset, nebo null.
        /// Lze setovat.
        /// Pokud je setován preset, který není v seznamu this.Presets, pak co? Pak je preset korektně do seznamu přidán (samozřejmě, kromě null hodnoty).
        /// </summary>
        internal Preset CurrentPreset
        {
            get
            {
                return this._CurrentPreset; 
            }
            set
            {
                if (value == null)
                {
                    this._CurrentPreset = null;
                }
                else
                {
                    bool exists = this._PresetList.Any(p => Object.ReferenceEquals(p, value));        // true: daný objekt je součástí našeho seznamu
                    if (!exists)
                        this.AddPreset(value);
                    this._CurrentPreset = value;
                }
            }
        }
        private Preset _CurrentPreset;
        /// <summary>
        /// Příznak true, pokud je vybrán nějaký preset v CurrentPreset
        /// </summary>
        internal bool HasCurrentPreset { get { return (this.CurrentPreset != null); } }
        /// <summary>
        /// ID vybraného Presetu (nebo "" pokud není vybrán). Hodnotu lze setovat, pak se vybere preset daného ID.
        /// Pokud se setuje ID neexistujícího presetu, nedojde k chybě, ale nebude vybrán žádný preset.
        /// </summary>
        internal string CurrentPresetID 
        {
            get { return (this.CurrentPreset == null ? "" : this.CurrentPreset.ID); }
            set { this.CurrentPreset = (String.IsNullOrEmpty(value) ? null : this._PresetList.FirstOrDefault(p => p.ID == value)); } 
        }
        private List<Preset> _PresetList;
        /// <summary>
        /// Souřadnice okna + jeho vizuální stav
        /// </summary>
        internal string FormPosition { get; set; }
        internal void Clear()
        {
            this._PresetList.Clear();
            this.CurrentPreset = null;
        }
        internal void ConfigLoad()
        {
            this.Clear();
            if (System.IO.File.Exists(this.ConfigFile))
            {
                XDocument xDoc = XDocument.Load(this.ConfigFile);
                XElement xRoot = xDoc.Root;
                if (xRoot != null && xRoot.Name.LocalName == "config")
                {
                    XElement xPresets = xRoot.Element("presets");
                    if (xPresets != null)
                    {
                        foreach (XElement xPreset in xPresets.Elements())
                        {
                            Preset preset = Preset.CreateFrom(xPreset);
                            if (preset != null)
                                this._PresetList.Add(preset);
                        }
                        this.CurrentPresetID = xPresets.GetAttributeString("CurrentID");
                        this.FormPosition = xPresets.GetAttributeString("FormBounds");
                    }
                }
            }
            if (this.CurrentPreset == null && this._PresetList.Count > 0)
                this.CurrentPreset = this._PresetList.Last();
        }
        internal void ConfigSave()
        {
            XDocument xDoc = new XDocument();
            
            XElement xRoot = new XElement("config");
            xRoot.AddAttribute("version", "1.0");
            xDoc.Add(xRoot);

            XElement xPresets = new XElement("presets");
            xRoot.Add(xPresets);

            xPresets.AddAttribute("CurrentID", this.CurrentPresetID);
            xPresets.AddAttribute("FormBounds", this.FormPosition);
            foreach (Preset preset in this._PresetList)
                xPresets.Add(preset.Serial);

            xDoc.Save(this.ConfigFile, true);
        }
        /// <summary>
        /// Přidá preset
        /// </summary>
        /// <param name="preset"></param>
        internal void AddPreset(Preset preset)
        {
            if (preset != null)
            {
                if (this._PresetList.Any(p => Object.ReferenceEquals(p, preset)))
                    throw new InvalidOperationException("Config.AddPreset(): preset already exists in Config.Presets !");
                if (String.IsNullOrEmpty(preset.ID) || this._PresetList.Any(p => p.ID == preset.ID))     // Pokud nový objekt nemá ID, nebo jeho ID se shoduje s ID některého stávajícího prvku, pak mu přidělím nové ID:
                    preset.ID = this.GetNextID();
                this._PresetList.Add(preset);
                if (!this.HasCurrentPreset)
                    this.CurrentPreset = preset;
            }
        }

        internal void RemovePreset(Preset preset)
        {
            if (preset != null)
            {
                this._PresetList.RemoveAll(p => Object.ReferenceEquals(p, preset));
                this.CurrentPreset = null;
            }
        }
        /// <summary>
        /// Vrací nové ID, které ještě v seznamu není.
        /// </summary>
        /// <returns></returns>
        private string GetNextID()
        {
            Random rand = new Random();
            for (int to = 0; to < 1000; to++)
            {
                string id = rand.Next(0x1000, 0xffff).ToString("X4");
                if (!this._PresetList.Any(p => p.ID == id))
                    return id;
            }
            return "";
        }
    }
}
